package com.sikaryofficial.backend.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.backend.constant.MyStatisticsTypeEnum;
import com.sikaryofficial.backend.constant.ReportConstant;
import com.sikaryofficial.backend.constant.WorkOrderStatusEnum;
import com.sikaryofficial.backend.domain.dto.req.workOrder.UserWorkOrderAcceptReq;
import com.sikaryofficial.backend.domain.dto.req.workOrder.UserWorkOrderListReq;
import com.sikaryofficial.backend.domain.dto.req.workOrder.UserWorkOrderSaveReq;
import com.sikaryofficial.backend.domain.dto.resp.workOrder.UserWorkOrderDTO;
import com.sikaryofficial.backend.domain.dto.resp.workOrder.UserWorkOrderDetailDTO;
import com.sikaryofficial.backend.domain.entity.Attachment;
import com.sikaryofficial.backend.domain.entity.UserReportLog;
import com.sikaryofficial.backend.domain.entity.UserWorkOrder;
import com.sikaryofficial.backend.domain.mapping.ReportMapping;
import com.sikaryofficial.backend.domain.mapping.UserWorkOrderMapping;
import com.sikaryofficial.backend.service.IAttachmentService;
import com.sikaryofficial.backend.service.IUserReportLogService;
import com.sikaryofficial.backend.service.IUserWorkOrderService;
import com.sikaryofficial.backend.service.address.AddressCacheService;
import com.sikaryofficial.backend.service.statistics.MyStatisticsProcessor;
import com.sikaryofficial.backend.service.statistics.MyStatisticsEvent;
import com.sikaryofficial.backend.service.statistics.MyStatisticsWithTenantEvent;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.StringUtils;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.model.AddressDTO;
import com.sikaryofficial.system.api.model.att.AttachmentResp;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc : 工单管理服务
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
@SuppressWarnings(value = "unchecked")
public class UserWorkOrderManager {
    @Autowired
    private IUserWorkOrderService userWorkOrderService;
    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private MyStatisticsProcessor myListener;
    @Autowired
    private IUserReportLogService reportLogService;
    @Autowired
    private AddressCacheService addressCacheService;
    @Autowired
    private DataRemoveManager dataRemoveManager;
    @NotNull
    private String buildWorkOrderNo(UserWorkOrder userWorkOrder) {
        String brandNo = userWorkOrder.getBrandNo();
        // brandNo 长度大于10,则截取前10位
        if(CharSequenceUtil.isBlank(brandNo)){
            brandNo = "";
        }else{
            brandNo = StringUtils.length(brandNo) > 10 ? brandNo.substring(0, 10) : brandNo;
        }
        return brandNo + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN) + StringUtils.genRandomStr(4);
    }

    /**
     * 保存工单
     *
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean workOrderSave(UserWorkOrderSaveReq req) {
        UserWorkOrder userWorkOrder = UserWorkOrderMapping.INSTANCE.coverReqToEntity(req);
        Long workOrderId = userWorkOrder.getWorkOrderId();
        if (Objects.isNull(workOrderId)) {
            workOrderId = IdWorker.getId();
        }
        String workOrderNo = buildWorkOrderNo(userWorkOrder);
        userWorkOrder.setWorkOrderId(workOrderId).setCreatedTime(new Date())
                .setWorkOrderNo(workOrderNo)
                .setCreatedBy(SecurityUtils.getUserId());
        // 保存工单
        boolean saveFlag = userWorkOrderService.saveOrUpdate(userWorkOrder);
        if (saveFlag) {
            // 保存附件
            attachmentService.saveAttachmentList(workOrderId, req.getAttachmentList(), SecurityUtils.getUserId());
        }
        // 2-增加统计信息
        myListener.addMyStatistics(new MyStatisticsEvent(MyStatisticsTypeEnum.WORK_ORDER_ACCEPTING.getBusinessType(), SecurityUtils.getUserId(), workOrderId));
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean accept(UserWorkOrderAcceptReq req) {
        UserWorkOrder userWorkOrder = userWorkOrderService.getOne(new LambdaQueryWrapper<UserWorkOrder>()
                .eq(UserWorkOrder::getDeletedVersion, 0L)
                .eq(UserWorkOrder::getWorkOrderId, req.getWorkOrderId())
                .eq(UserWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.ACCEPTING.getCode())
                .last(" limit 1 "));
        if (Objects.isNull(userWorkOrder)) {
            throw new ServiceException("the workOrder is not exist or has been accepted");
        }
        // 保存工单
        userWorkOrderService.update(new LambdaUpdateWrapper<UserWorkOrder>()
                .set(UserWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.ACCEPTED.getCode())
                .set(UserWorkOrder::getUpdatedTime, new Date())
                .set(UserWorkOrder::getUpdatedBy, SecurityUtils.getUserId())
                .eq(UserWorkOrder::getWorkOrderId, req.getWorkOrderId())
                .eq(UserWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.ACCEPTING.getCode())
        );
        // 2- 工单日志
        UserReportLog reportLog = UserReportLog.builder()
                .reportLogId(IdWorker.getId())
                .reportId(req.getWorkOrderId())
                .tenantId(userWorkOrder.getTenantId())
                .remark(req.getRemark())
                .createdName(SecurityUtils.getUsername())
                .createdBy(SecurityUtils.getUserId())
                .createdTime(new Date())
                .build();
        reportLogService.save(reportLog);
        // 2-增加统计信息
        myListener.addMyStatisticsWithTenant(new MyStatisticsWithTenantEvent(MyStatisticsTypeEnum.WORK_ORDER_ACCEPTING.getBusinessType(), SecurityUtils.getUserId(),
                req.getWorkOrderId(), userWorkOrder.getTenantId()));
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(Long workOrderId) {
        // 删除工单主表
        userWorkOrderService.update(new LambdaUpdateWrapper<UserWorkOrder>()
                .setSql("  deleted_version = work_order_id ")
                .set(UserWorkOrder::getUpdatedBy, SecurityUtils.getUserId())
                .set(UserWorkOrder::getUpdatedTime, new Date())
                .eq(UserWorkOrder::getWorkOrderId, workOrderId)
        );
        // 删除日志信息
        reportLogService.update(new LambdaUpdateWrapper<UserReportLog>()
                .setSql("  deleted_version = report_log_id ")
                .set(UserReportLog::getUpdatedBy, SecurityUtils.getUserId())
                .set(UserReportLog::getUpdatedTime, new Date())
                .eq(UserReportLog::getReportId, workOrderId)
        );
        // 删除附件
        attachmentService.update(new LambdaUpdateWrapper<Attachment>()
                .setSql("  deleted_version = attachment_id ")
                .set(Attachment::getUpdatedBy, SecurityUtils.getUserId())
                .set(Attachment::getUpdatedTime, new Date())
                .eq(Attachment::getObjectId, workOrderId)
        );
        // 删除统计数据
        dataRemoveManager.removeStatics(workOrderId);
        return true;
    }

    /**
     * 工单列表
     *
     * @param req
     * @return
     */
    public IPage<UserWorkOrderDTO> listPage(UserWorkOrderListReq req) {
        Page<UserWorkOrder> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        if (Objects.isNull(req.getUserId()) && req.getUserId() <= 0) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        IPage<UserWorkOrder> result = userWorkOrderService.page(customerPage,
                new LambdaQueryWrapper<UserWorkOrder>()
                        .eq(UserWorkOrder::getDeletedVersion, 0L)
                        .eq(Objects.nonNull(req.getUserId()), UserWorkOrder::getCreatedBy, req.getUserId())
                        .orderByDesc(UserWorkOrder::getCreatedTime, UserWorkOrder::getWorkOrderStatus));
        if (CollUtil.isEmpty(result.getRecords())) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        IPage<UserWorkOrderDTO> reportDTOIPage = result.convert(UserWorkOrderMapping.INSTANCE::coverToDTO);
        List<UserWorkOrderDTO> reportDTOList = reportDTOIPage.getRecords();
        if (CollUtil.isEmpty(reportDTOList)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        buildExtData(reportDTOList, req);
        return reportDTOIPage;
    }

    /**
     * 填充扩展数据
     *
     * @param reportDTOList
     */
    private void buildExtData(List<UserWorkOrderDTO> reportDTOList, UserWorkOrderListReq req) {
        Map<Long, List<AttachmentResp>> attachmentMap = attachmentService.getAttachmentByIds(reportDTOList.stream().map(UserWorkOrderDTO::getWorkOrderId).collect(Collectors.toList()));
        // 设置序号
        AtomicInteger rowNum = new AtomicInteger(1);
        reportDTOList.forEach(item -> {
            item.setSeqNo((req.getPageNum() - 1) * req.getPageSize() + rowNum.get());
            rowNum.getAndIncrement();
            // 填充状态
            item.setWorkOrderStatusDesc(WorkOrderStatusEnum.getDescByCode(item.getWorkOrderStatus()));
            // 填充图片
            if (attachmentMap.containsKey(item.getWorkOrderId())) {
                List<AttachmentResp> attachments = attachmentMap.get(item.getWorkOrderId());
                if (CollUtil.isEmpty(attachments)) {
                    return;
                }
                AttachmentResp coverAtt = attachments.stream().filter(attachment -> Objects.equals(attachment.getHasCover(), 1)).findFirst().orElse(new AttachmentResp());
                item.setCoverUrl(coverAtt.getUrl());
            }
        });
    }

    /**
     * 获取工单详情
     *
     * @param workOrderId
     * @return
     */
    public UserWorkOrderDetailDTO detail(Long workOrderId) {
        if (Objects.isNull(workOrderId) || workOrderId <= 0) {
            return null;
        }
        UserWorkOrder workOrder = userWorkOrderService.getOne(new LambdaQueryWrapper<UserWorkOrder>()
                .eq(UserWorkOrder::getWorkOrderId, workOrderId).eq(UserWorkOrder::getDeletedVersion, 0L)
                .last(" limit 1"));
        UserWorkOrderDetailDTO detailDTO = UserWorkOrderMapping.INSTANCE.coverToDetailDTO(workOrder);
        if (Objects.nonNull(detailDTO)) {
            // 附件
            detailDTO.setAttachmentList(attachmentService.getAttachmentById(workOrderId));
            detailDTO.setWorkOrderStatusDesc(WorkOrderStatusEnum.getDescByCode(detailDTO.getWorkOrderStatus()));
        }
        if (Objects.nonNull(detailDTO) && ReportConstant.ACCEPTED.equals(detailDTO.getWorkOrderStatus())) {
            // 获取举报日志最新的记录
            List<UserReportLog> reportLogList = reportLogService.list(new LambdaQueryWrapper<UserReportLog>().eq(UserReportLog::getReportId, workOrderId).eq(UserReportLog::getDeletedVersion, 0L).orderByDesc(UserReportLog::getCreatedTime).last(" limit 1"));
            detailDTO.setReportLogList(ReportMapping.INSTANCE.coverLogToDTOList(reportLogList));
        }
        return detailDTO;
    }

    public IPage<UserWorkOrderDTO> backendList(UserWorkOrderListReq req) {
        Page<UserWorkOrder> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        List<AddressDTO> addressDTOList = addressCacheService.getAllAddressByCountry();
        List<Long> addressIds = addressDTOList.stream().filter(item -> CharSequenceUtil.isNotBlank(req.getCountry()) && item.getCountry().equals(req.getCountry()))
                .filter(item -> CharSequenceUtil.isNotBlank(req.getArea()) && item.getArea().equals(req.getArea()))
                .filter(item -> CharSequenceUtil.isNotBlank(req.getCity()) && item.getCity().equals(req.getCity()))
                .map(AddressDTO::getAddressId).collect(Collectors.toList());

        LambdaQueryWrapper<UserWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(UserWorkOrder::getWorkOrderId, UserWorkOrder::getWorkOrderStatus,
                        UserWorkOrder::getBrandNo, UserWorkOrder::getProductName,
                        UserWorkOrder::getWorkOrderNo, UserWorkOrder::getFirstName,
                        UserWorkOrder::getLastName, UserWorkOrder::getEmail,
                        UserWorkOrder::getRemark,
                        UserWorkOrder::getCreatedTime, UserWorkOrder::getAddressId,
                        UserWorkOrder::getCountry,UserWorkOrder::getArea,UserWorkOrder::getCity
                )
                .eq(UserWorkOrder::getDeletedVersion, 0L)
                .eq(Objects.nonNull(req.getUserId()), UserWorkOrder::getCreatedBy, req.getUserId())
                .eq(CharSequenceUtil.isNotBlank(req.getBrandNo()), UserWorkOrder::getBrandNo, req.getBrandNo())
                .likeRight(CharSequenceUtil.isNotBlank(req.getProductName()), UserWorkOrder::getProductName, req.getProductName())
                .likeRight(CharSequenceUtil.isNotBlank(req.getWorkOrderNo()), UserWorkOrder::getWorkOrderNo, req.getWorkOrderNo())
                .eq(CharSequenceUtil.isNotBlank(req.getCountry()), UserWorkOrder::getCountry, req.getCountry())
                .eq(CharSequenceUtil.isNotBlank(req.getArea()), UserWorkOrder::getArea, req.getArea())
                .eq(CharSequenceUtil.isNotBlank(req.getCity()), UserWorkOrder::getCity, req.getCity())
                .in(CollUtil.isNotEmpty(addressIds), UserWorkOrder::getAddressId, addressIds)
        ;

        if (CharSequenceUtil.isNotBlank(req.getPromoter())) {
            queryWrapper.and(
                    i -> i.likeRight(CharSequenceUtil.isNotBlank(req.getPromoter()), UserWorkOrder::getFirstName, req.getPromoter())
                            .or().likeRight(CharSequenceUtil.isNotBlank(req.getPromoter()), UserWorkOrder::getLastName, req.getPromoter())
            );
        }
        if (Objects.nonNull(req.getStartTime()) && Objects.nonNull(req.getEndTime())) {
            queryWrapper.and(i -> i.between(UserWorkOrder::getCreatedTime, req.getStartTime(), req.getEndTime()));
        }
        queryWrapper.orderByDesc(UserWorkOrder::getCreatedTime, UserWorkOrder::getWorkOrderStatus);

        IPage<UserWorkOrder> result = userWorkOrderService.page(customerPage, queryWrapper);
        if (CollUtil.isEmpty(result.getRecords())) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        IPage<UserWorkOrderDTO> reportDTOIPage = result.convert(UserWorkOrderMapping.INSTANCE::coverToDTO);
        List<UserWorkOrderDTO> reportDTOList = reportDTOIPage.getRecords();
        if (CollUtil.isEmpty(reportDTOList)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        buildExtData(reportDTOList, req);
        return reportDTOIPage;
    }
}
